using System;
using System.Activities;
using Microsoft.Xrm.Sdk.Workflow;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Globalization;
using Microsoft.Xrm.Sdk.Messages;

namespace CRM2011WorkflowUtilities
{
    public class CreateHyperLink : CodeActivity
    {
        protected override void Execute(CodeActivityContext executionContext)
        {
            try
            {
                //Create the context and tracing service
                IExecutionContext context = executionContext.GetExtension<IExecutionContext>();
                IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
                ITracingService tracer = executionContext.GetExtension<ITracingService>();

                if (PrimaryEntity.Get(executionContext))
                {
                    tracer.Trace("Generating hyperlink to the primary entity");
                    GenerateHyperLink(new EntityReference(context.PrimaryEntityName, context.PrimaryEntityId), executionContext, service, tracer);
                }
                else
                {
                    string relatedAttribute = RelatedAttributeName.Get(executionContext);
                    if (string.IsNullOrEmpty(relatedAttribute))
                    {
                        Helpers.Throw("If creating hyperlink to related entity, related attribute name must be specified in the process step configuration");
                    }

                    // Retrieve primary entity with the required attribute
                    tracer.Trace("Retrieving process primary entity");
                    Entity primaryEntity = service.Retrieve(context.PrimaryEntityName, context.PrimaryEntityId, new ColumnSet(relatedAttribute));

                    if (primaryEntity.Contains(relatedAttribute))
                    {
                        EntityReference reference = primaryEntity[relatedAttribute] as EntityReference;
                        if (reference == null)
                        {
                            Helpers.Throw(string.Format("The attribute {0} on entity {1} is expected to be of EntityReference type",
                                relatedAttribute, context.PrimaryEntityName));
                        }

                        tracer.Trace("Creating hyperlink to entity related to primary entity by attribute " + relatedAttribute);
                        GenerateHyperLink(reference, executionContext, service, tracer);
                    }

                }
                

            }
            catch (Exception ex)
            {
               Helpers.Throw(String.Format("An error occurred in the {0} plug-in.",
                       this.GetType().ToString()),
                     ex);
            }

            return;
        }

        private void GenerateHyperLink(EntityReference entityReference, CodeActivityContext context, IOrganizationService service, ITracingService tracer)
        {
            string url = string.Format(CultureInfo.InvariantCulture, UrlFormat,
                 OrganizationUrl.Get(context),
                 entityReference.LogicalName,
                entityReference.Id);

            string hyperLinkText = HyperLinkText.Get(context);
            if (string.IsNullOrEmpty(hyperLinkText))
            {
                tracer.Trace("Retrieving primary field of entity to use as hyperlink text");
                hyperLinkText = GetHyperLinkText(entityReference, service);
            }
            string htmlHyperLink = string.Format(CultureInfo.InvariantCulture, HyperLinkFormat,
                url,
                hyperLinkText);
            HtmlHyperLink.Set(context, htmlHyperLink);

            string dialogHyperLink = string.Format(CultureInfo.InvariantCulture, DialogLinkFormat,
                 hyperLinkText,
                 url);

            DialogHyperLink.Set(context, dialogHyperLink);
        }

        private string GetHyperLinkText(EntityReference entityReference, IOrganizationService service)
        {
            RetrieveEntityRequest req = new RetrieveEntityRequest
            {
                LogicalName = entityReference.LogicalName,
            };
            RetrieveEntityResponse resp = (RetrieveEntityResponse)service.Execute(req);

            Entity entity = service.Retrieve(entityReference.LogicalName, entityReference.Id, new ColumnSet(resp.EntityMetadata.PrimaryNameAttribute));
            string text = entity[resp.EntityMetadata.PrimaryNameAttribute] as string;
            if (string.IsNullOrEmpty(text))
            {
                // Default text if none specified and entity does not have primary field
                text = "HyperLink";
            }
            return text;
        }

        #region Input Parameters

        [RequiredArgument]
        [Input("URL of the CRM Organization (e.g. 'http://mycrm/myOrg'")]
        public InArgument<string> OrganizationUrl { get; set; }

        [RequiredArgument]
        [Input("HyperLink to primary entity (True) or related entity (False)")]
        public InArgument<bool> PrimaryEntity { get; set; }

        [Input("If creating hyperling to related entity, specify attribute name to get the related entity")]
        public InArgument<string> RelatedAttributeName { get; set; }

        [Input("HyperLink text. If not provided, entity primary field name will be used.")]
        public InArgument<string> HyperLinkText { get; set; }

        #endregion

        #region Output Parameters

        [Output("HtmlHyperLink")]
        public OutArgument<string> HtmlHyperLink { get; set; }

        [Output("DialogHyperLink")]
        public OutArgument<string> DialogHyperLink { get; set; }

        #endregion

        #region Private members

        private static string UrlFormat = @"{0}/main.aspx?etn={1}&pagetype=entityrecord&id=%7B{2}%7D";
        private static string HyperLinkFormat = @"<a href='{0}'>{1}</a>";
        private static string DialogLinkFormat = @"<hyperlink><name>{0}</name><value>{1}</value></hyperlink>";

        #endregion
    }
}
